package com.example.testapp.activity.util;

import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;

import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * bitmap操作的工具类
 * Created by l on 2016/10/25.
 */

public class BitmapUtils {

    private static final String TAG = "BitmapUtils";
    private static final int DEFAULT_COMPRESS_QUALITY = 90;
    private static final int INDEX_ORIENTATION = 0;

    private static final String[] IMAGE_PROJECTION = new String[] {
            MediaStore.Images.ImageColumns.ORIENTATION
    };

    private final Context context;

    public BitmapUtils(Context mContext) {
         this.context = mContext;
    }

    public Rect getBitmapBounds(Uri uri) {
        Rect  bounds = new Rect();
        InputStream is = null;

        try {
            is = context.getContentResolver().openInputStream(uri);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is, null, options);

            bounds.right = options.outWidth;
            bounds.bottom = options.outHeight;
            Log.i(TAG, "options.outWidth="+options.outWidth+" , "+"options.outHeight="+options.outHeight);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            closeStream(is);
        }
        return bounds;
    }

    private void closeStream(Closeable stream) {
         if (stream != null){
             try {
                 stream.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
    }

    /**
     * Gets decoded bitmap that keeps orientation as well.
     */
    public Bitmap getBitmap(Uri uri, int width, int height) {
        Bitmap bitmap = decodeBitmap(uri, width, height);

        if (bitmap != null){
            int orientation = getOrientation(uri);
            if (orientation != 0){
                Matrix m = new Matrix();
                m.setRotate(orientation);
                Bitmap transformed = createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m);
                bitmap.recycle();
                return transformed;
            }
        }
        return bitmap;
    }

    private int getOrientation(Uri uri) {
        int orientation = 0;
        Cursor cursor = null;

        try {
            cursor = context.getContentResolver().query(uri, IMAGE_PROJECTION, null, null, null);
            if ((cursor != null) && cursor.moveToNext() ){
                orientation = cursor.getInt(INDEX_ORIENTATION);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (cursor != null){
                cursor.close();
            }
        }
        return orientation;
    }

    private Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m) {
        Canvas canvas = new Canvas();

        Bitmap bitmap;
        Paint paint;
        if ((m == null) || m.isIdentity()){
            bitmap = Bitmap.createBitmap(width, height, source.getConfig());
            paint = null;
        }else{
            RectF rect = new RectF(0, 0, width, height);
            m.mapRect(rect);
            bitmap = Bitmap.createBitmap(Math.round(rect.width()), Math.round(rect.height()), source.getConfig());

            canvas.translate(-rect.left, -rect.top);
            canvas.concat(m);

            paint = new Paint(Paint.FILTER_BITMAP_FLAG);
            if (!m.rectStaysRect()){
                paint.setAntiAlias(true);
            }
        }
        bitmap.setDensity(source.getDensity());
        canvas.setBitmap(bitmap);

        Rect  srcBounds = new Rect(x, y, x + width, y + height);
        RectF dstBounds = new RectF(0, 0, width, height);
        canvas.drawBitmap(bitmap, srcBounds,dstBounds, paint);
        return bitmap;
    }

    /**
     * Decodes bitmap (maybe immutable) that keeps aspect-ratio and spans most within the bounds.
     */
    private Bitmap decodeBitmap(Uri uri, int width, int height) {
        Log.i(TAG, "width = " + width + " , " + "height = " + height);
        InputStream  is = null;
        Bitmap  bitmap = null;

        try {
            Rect bounds = getBitmapBounds(uri);
            int  sampleSize = Math.max(bounds.width()/width, bounds.height()/height);
            sampleSize = Math.min(sampleSize, Math.max(bounds.width() / height, bounds.height() / width));

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inSampleSize = Math.max(sampleSize, 1);
            options.inPreferredConfig = Bitmap.Config.ARGB_8888;
            is = context.getContentResolver().openInputStream(uri);
            Log.i(TAG, "sampleSize = " + sampleSize + " , " + "options.inSampleSize = " + options.inSampleSize);
            bitmap = BitmapFactory.decodeStream(is, null, options);
        }catch (Exception e){
             e.printStackTrace();
        }finally {
             closeStream(is);
        }

        // Ensure bitmap in 8888 format, good for editing as well as GL compatible.
        if ((bitmap != null) && (bitmap.getConfig() != Bitmap.Config.ARGB_8888)){
            Bitmap copy = bitmap.copy(Bitmap.Config.ARGB_8888, true);
            bitmap.recycle();
            bitmap = copy;
        }

        if (bitmap != null){
            // Scale down the sampled bitmap if it's still larger than the desired dimension.
            float scale = Math.min((float)width / bitmap.getWidth(), (float) height / bitmap.getHeight());
            scale = Math.max(scale, Math.min((float) height / bitmap.getWidth(), (float) width / bitmap.getHeight()));
            if (scale < 1){
                Matrix m = new Matrix();
                m.setScale(scale, scale);
                Bitmap transformed = createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m);
                bitmap.recycle();
                return transformed;
            }
        }
        return bitmap;
    }

    /**
     * Saves the bitmap by given directory, filename, and format; if the directory is given null,
     * then saves it under the cache directory.
     */
    public File saveBitmap(Bitmap bitmap, String directory, String filename, Bitmap.CompressFormat format) {
        if (directory == null){
            directory = context.getCacheDir().getAbsolutePath();
        }else {
            // Check if the given directory exists or try to create it.
            File file = new File(directory);
            if (!file.isDirectory() && !file.mkdirs()){
                return null;
            }
        }

        File file = null;
        OutputStream os = null;

        try {
            filename = (format == Bitmap.CompressFormat.PNG) ? filename + ".png" : filename + ".jpg";
            file = new File(directory, filename);
            os = new FileOutputStream(file);
            bitmap.compress(format, DEFAULT_COMPRESS_QUALITY, os);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            closeStream(os);
        }
        return file;
    }
}
